<template>
  <teleport to="body">
    <transition name="fade">
      <div v-if="modelValue" class="dialog-overlay" @click.self="handleClickOutside">
        <div class="dialog-content" :style="contentStyle">
          <header class="dialog-header" v-if="title">
            <span style="color: #c0e4ff;font-size: 16px">{{ title }}</span>
            <button class="close-button" @click="close">&times;</button>
          </header>

          <div class="dialog-body">
            <slot></slot>
          </div>

          <footer class="dialog-footer" v-if="$slots.footer">
            <slot name="footer"></slot>
          </footer>
        </div>
      </div>
    </transition>
  </teleport>
</template>

<script lang="ts">
import { defineComponent, computed, watch, onMounted, onUnmounted, StyleValue } from 'vue';

export default defineComponent({
  name: 'Dialog',
  props: {
    modelValue: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: ''
    },
    width: {
      type: [String, Number] as () => string | number,
      default: '500px'
    },
    closeOnClickOutside: {
      type: Boolean,
      default: true
    },
    closeOnEsc: {
      type: Boolean,
      default: true
    },
    lockScroll: {
      type: Boolean,
      default: true
    }
  },
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    const isOpen = computed({
      get: () => props.modelValue,
      set: (value: boolean) => emit('update:modelValue', value)
    });

    const contentStyle = computed<StyleValue>(() => ({
      width: typeof props.width === 'number' ? `${props.width}px` : props.width
    }));

    const open = (): void => {
      isOpen.value = true;
    };

    const close = (): void => {
      isOpen.value = false;
    };

    const handleClickOutside = (): void => {
      if (props.closeOnClickOutside) {
        close();
      }
    };

    const handleKeydown = (e: KeyboardEvent): void => {
      if (e.key === 'Escape' && props.closeOnEsc && props.modelValue) {
        close();
      }
    };

    const lockBodyScroll = (): void => {
      if (props.lockScroll) {
        document.body.style.overflow = 'hidden';
      }
    };

    const unlockBodyScroll = (): void => {
      if (props.lockScroll) {
        document.body.style.overflow = '';
      }
    };

    onMounted(() => {
      window.addEventListener('keydown', handleKeydown);
    });

    onUnmounted(() => {
      window.removeEventListener('keydown', handleKeydown);
      unlockBodyScroll();
    });

    watch(() => props.modelValue, (newVal) => {
      if (newVal) {
        lockBodyScroll();
      } else {
        unlockBodyScroll();
      }
    });

    return {
      isOpen,
      contentStyle,
      open,
      close,
      handleClickOutside
    };
  }
});
</script>

<style scoped>
.org-dialog {
  background-color: rgba(6, 27, 46, .7);
  border: 1px solid #74cefd;
  -webkit-box-shadow: rgba(127, 192, 236, .5) 0 8px 24px;
  box-shadow: 0 8px 24px rgba(127, 192, 236, .5);
}
.dialog-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.dialog-content {
  background-color: rgba(6, 27, 46, .7);
  border: 1px solid #74cefd;
  -webkit-box-shadow: rgba(127, 192, 236, .5) 0 8px 24px;
  box-shadow: 0 8px 24px rgba(127, 192, 236, .5);
  /*background: white;*/
  /*border-radius: 8px;*/
  /*box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);*/
  /*max-height: 80vh;*/
  /*display: flex;*/
  /*flex-direction: column;*/
  /*overflow: hidden;*/
}

.dialog-header {
  padding: 16px 24px;
  border-bottom: 1px solid rgba(192, 228, 255, .32);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dialog-header h2 {
  margin: 0;
  font-size: 1.25rem;
}

.close-button {
  background: none;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
  padding: 0 8px;
}

.dialog-body {
  padding: 24px;
  overflow-y: auto;
  flex-grow: 1;
}

.dialog-footer {
  padding: 16px 24px;
  border-top: 1px solid rgba(192, 228, 255, .32);  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* 动画效果 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  /*opacity: 0;*/
}
</style>
